<?php

declare(strict_types=1);

namespace DreamCat\ObjectValid\Annotation;

use Attribute;
use DreamCat\ObjectValid\Base\ValidAnnoInterface;
use DreamCat\ObjectValid\Utils\ReflectionUtils;
use JetBrains\PhpStorm\Immutable;
use ReflectionParameter;
use ReflectionProperty;

/**
 * -
 * @author vijay
 */
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_PARAMETER | Attribute::IS_REPEATABLE)]
#[Immutable]
class Size implements ValidAnnoInterface
{
    /**
     * @param int|null $sizeMin 最小值，null表示不限制
     * @param int|null $sizeMax 最大值，null表示不限制
     * @param string|null $message 错误信息
     */
    public function __construct(
        private ?int $sizeMin = null,
        private ?int $sizeMax = null,
        private ?string $message = null
    ) {
    }

    /**
     * @return int|null 最小值，null表示不限制
     */
    public function getSizeMin(): ?int
    {
        return $this->sizeMin;
    }

    /**
     * @return int|null 最大值，null表示不限制
     */
    public function getSizeMax(): ?int
    {
        return $this->sizeMax;
    }

    /**
     * @return string|null 错误信息
     */
    public function getMessage(): ?string
    {
        return $this->message;
    }

    /**
     * @inheritDoc
     */
    public function errorMessage(ReflectionParameter|ReflectionProperty $reflection, mixed $value): string
    {
        if (!is_null($this->message)) {
            return $this->message;
        }
        $list = [];
        if ($this->sizeMax !== null) {
            $list[] = "不能大于 {$this->sizeMax}";
        }
        if ($this->sizeMin !== null) {
            $list[] = "不能小于 {$this->sizeMin}";
        }
        return ReflectionUtils::getReflectDesc($reflection) .  " 的 size " . implode(" 且", $list);
    }

    /**
     * @inheritDoc
     */
    public function isValid(mixed $value): bool
    {
        if ($value === null) {
            return true;
        }
        if (is_array($value) || is_object($value)) {
            $size = count($value);
        } else {
            $size = mb_strlen(strval($value));
        }

        if ($this->sizeMax !== null && $size > $this->sizeMax) {
            return false;
        }
        if ($this->sizeMin !== null && $size < $this->sizeMin) {
            return false;
        }
        return true;
    }
}

# end of file
